//
//  DBCommunicator.m
//  Seizure
//
//  Created by student on 2/23/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "DBCommunicator.h"
#import "AFHTTPClient.h"
#import "AFXMLRequestOperation.h"
#import "XMLDefaultDelegate.h"
#import "XMLLoginDelegate.h"
#import "XMLReadCaretakers.h"
#import "XMLGetSensitivity.h"
#import "XMLReadEventLogs.h"
#import "LoadingAlert.h"
#import "DataManager.h"

@implementation DBCommunicator

static NSString *BASE_URL = @"http://elvis.rowan.edu/~rennt79/iphone/",
                *POST_NAME = @"name",
                *POST_EMAIL = @"email",
                *POST_APNS = @"apns",
                *POST_PASSWORD = @"password",
                *POST_ACC_TYPE = @"type",
                *POST_TARGET = @"target",
                *POST_SENSITIVITY = @"sensitivity",
                *POST_START_TIME = @"start",
                *POST_END_TIME = @"end",
                *POST_LATITUDE = @"latitude",
                *POST_LONGITUDE = @"longitude",
                *POST_ACCURACY = @"accuracy";
BOOL debug = YES;


/* Hash a string into SHA256
 * Stolen from: http://stackoverflow.com/a/4995996
 */
-(NSString*) sha256:(NSString *)clear{
    const char *s=[clear cStringUsingEncoding:NSASCIIStringEncoding];
    NSData *keyData=[NSData dataWithBytes:s length:strlen(s)];
    
    uint8_t digest[CC_SHA256_DIGEST_LENGTH]={0};
    CC_SHA256(keyData.bytes, keyData.length, digest);
    NSData *out=[NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH];
    NSString *hash=[out description];
    hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""];
    hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""];
    hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""];
    return hash;
}

// return patient type as a string
-(NSString*) getPatientType:(Account*)account {
    if ([account isPatient])
        return @"patient";
    else
        return @"caretaker";
}

/* register a new account
 *
 * @param Account user
 * @param NSString password
 */
- (void)registerUser:(Account*)user password:(NSString*)password delegate:(id<NetworkData>)delegate requestType:(short)rtype{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    password = [self sha256:password];
    
    NSString *apnsKey = user.apnsKey;
    if ([apnsKey isEqualToString:@""]){
        apnsKey = @"temporary_apns_key";
    }
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            user.email, POST_EMAIL,
                            user.name, POST_NAME,
                            apnsKey, POST_APNS,
                            [self getPatientType:user], POST_ACC_TYPE,
                            password, POST_PASSWORD,
                            nil];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"account/register.php" parameters:params];
    
    __block id<NetworkData> target = delegate;
    __block short type = rtype;
    __block Account* account = user;
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
            success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
                
                    XMLDefaultDelegate *handler = [[XMLDefaultDelegate alloc] init];
                    [XMLParser setDelegate:(id)handler];
                    
                    [XMLParser parse];
                
                    NSString *result = [handler result];
                    
                    result = [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
                
                    // no error if empty string
                    if ([result isEqualToString:@""])
                        [target DataArrived:account requestType:type];
                    else
                        [target DataArrived:result requestType:type];
            }
              failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , NSXMLParser *XMLParse) {
                    // something went wrong
                    [target DataArrived:nil requestType:type];
            }];


    [operation start];
}



/* Login a user
 *
 * @param NSString email
 * @param NSString password
 * @return null if information was wrong, otherwise account information 
 */
- (void) loginUser:(NSString*)email password:(NSString*)password delegate:(id<NetworkData>)delegate requestType:(short)rtype{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    password = [self sha256:password];
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            email, POST_EMAIL,
                            password, POST_PASSWORD,
                            nil];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"account/login.php" parameters:params];
    
    
    __block id<NetworkData> target = delegate;
    __block int requestType = rtype;
    // __block int x = 1;
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
        success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
                                                                                               
            XMLLoginDelegate *handler = [[XMLLoginDelegate alloc] init];
            [XMLParser setDelegate:handler];
            [XMLParser parse];
            [target DataArrived:[handler createdAccount] requestType:requestType];
                                                                                               
    }
        failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , NSXMLParser *XMLParse) {
            // something went wrong
            [target DataArrived:nil requestType:0];
    }];
    
    [operation start];
}

/**
 *  Makes a request to createResetLink.php that will email the user a link to reset their password with.
 *  Parameters: email -- The email to email reset link to.
 *  Silent on successful email send.
 */
- (BOOL) resetPassword:(NSString*)email
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            email, POST_EMAIL, nil];
    
    
    NSMutableURLRequest *urlRequest = [httpClient requestWithMethod:@"GET" path:@"account/createResetLink.php" parameters:params];
    AFXMLRequestOperation *operation = [[AFXMLRequestOperation alloc] initWithRequest:urlRequest];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
    [queue waitUntilAllOperationsAreFinished];

    //If the responseString says Success -- EMAIL SENT
    if( [[operation responseString] isEqualToString:@"\nSuccess"] )
    {
        return true;
    }
    else
        return false;
}

/**
 * Parameters: requestingAccount - The account of the current user.
 *              email - The email the user is trying to create a connection to.
 * This method is used by Patients requesting Caretakers and vice versa.
 */
//TODO: CHECK RESPONSE STRING TO SEE IF OPERATION WAS SUCCESSFUL OR NOT.
- (NSString*) createPatientCaretakerConnection: (Account *)requestingAccount emailOfRequested:(NSString *)email
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    //Default is to make the account type caretaker. If it's actually patient, it will switch.
    NSString *type = @"caretaker";
    if( requestingAccount.isPatient )
    {
        type = @"patient";
    }
    NSString *requesterEmail = requestingAccount.email;
    NSString *targetEmail = email;
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                                requesterEmail, POST_EMAIL, 
                                type, POST_ACC_TYPE, 
                                targetEmail, POST_TARGET, nil];
    
    NSMutableURLRequest *urlRequest = [httpClient requestWithMethod:@"POST" path:@"connections/addConnection.php" parameters:params];
    AFXMLRequestOperation *operation = [[AFXMLRequestOperation alloc] initWithRequest:urlRequest];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
    [queue waitUntilAllOperationsAreFinished];
    
    // get XML parser and read xml
    NSXMLParser *parser = [operation responseXMLParser];
    XMLDefaultDelegate *handler = [[XMLDefaultDelegate alloc] init];
    [parser setDelegate:handler];
    [parser parse];
    NSString *result = [handler result];
    
    
    if (debug)
        NSLog(@" data--Create Connection\n %@", [operation responseString]);
    
    return result;
}

/**
 * Parameters: initiatingAccount - The account of the current user.
 *              email - The email the user is trying to break a connection with.
 * This method is used by Patients disconnecting from Caretakers and vice versa.
 */
//TODO: CHECK RESPONSESTRING TO SEE IF OPERATION WAS SUCCESSFUL OR NOT
- (BOOL)removePatientCaretakerConnection:(Account *)initiatingAccount emailToDisconnect:(NSString *)email
{
    //TODO: TRY REMOVING FROM DATABASE... And Stuff.
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    //Default is to make the account type caretaker. If it's actually patient, it will switch.
    NSString *type = @"caretaker";
    if( initiatingAccount.isPatient )
    {
        type = @"patient";
    }
    NSString *initiaterEmail = initiatingAccount.email;
    NSString *targetEmail = email;
    
    NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:
                                initiaterEmail, POST_EMAIL,
                                type, POST_ACC_TYPE,
                                targetEmail, POST_TARGET, nil];
    
    NSMutableURLRequest *urlRequest = [httpClient requestWithMethod:@"POST" path:@"connections/removeConnection.php" parameters:params];
    AFXMLRequestOperation *operation = [[AFXMLRequestOperation alloc] initWithRequest:urlRequest];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
    [queue waitUntilAllOperationsAreFinished];
    if (debug)
        NSLog(@" data--Remove Connection\n %@", [operation responseString]);
    
    return TRUE;
}

/**
 * Parameters: caretakersEmail - The email of the caretaker is all that is needed because this patient and caretaker
 combination has already been set up. 
 * This method is used by Patients confirming a Caretaker and vice versa.
 */
//TODO: CHECK RESPONSE STRING TO SEE IF OPERATION WAS SUCCESSFUL OR NOT
- (BOOL)confirmPatientCaretakerConnection:(NSString *)caretakersEmail
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:caretakersEmail, POST_EMAIL, nil];
    NSMutableURLRequest *urlRequest = [httpClient requestWithMethod:@"POST" path:@"connections/acceptConnection.php" parameters:params];
    AFXMLRequestOperation *operation = [[AFXMLRequestOperation alloc] initWithRequest:urlRequest];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
    [queue waitUntilAllOperationsAreFinished];
    if (debug)
        NSLog(@"data--confirm Connection\n %@", [operation responseString]);
    
    return TRUE;
}

/**
 *  Parameters: patient's email - The email of the patient whose sensitivity has changed.
 *              sensitivity - The value to change the sensitivity to. Valid numbers range from 0 - 100 inclusive.
 *  This method can be used by either a patient or a caretaker
 */
-(BOOL)updatePatientSensitivity:(NSString *)patientEmail sensitivity:(NSNumber *)sensitivity
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
                            patientEmail, POST_EMAIL, 
                            sensitivity, POST_SENSITIVITY,
                            nil];
    NSMutableURLRequest *urlRequest = [httpClient requestWithMethod:@"POST" path:@"account/updateSensitivity.php" parameters:params];
            
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:urlRequest 
            success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
                // Server took care of updating APNS key, no need to notify user    
            }
            failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , NSXMLParser *XMLParse) {
                // some failure
            }];
    
    [operation start];
    
    if(debug)
        NSLog(@"data--updatePatientSensitivity\n %@",[operation responseString]);
    
    return TRUE;
}

/**
 * Returns the current Patient's sensitivity
 */
- (NSNumber*)getPatientSensitivity:(NSString *)patientEmail
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys: 
                            patientEmail, POST_EMAIL, 
                            nil];
    NSMutableURLRequest *urlRequest = [httpClient requestWithMethod:@"POST" path:@"requests/getSensitivity.php" parameters:params];
    
    AFXMLRequestOperation *operation = [[AFXMLRequestOperation alloc] initWithRequest:urlRequest];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
    [queue waitUntilAllOperationsAreFinished];
    if(debug)
        NSLog(@"data--getPatientSensitivity\n %@",[operation responseString]);
    
    NSNumber *n;
    if (![operation hasAcceptableStatusCode] || [operation response] == nil){
        // operation failed
    }
    else {
        // check response, validate success
        XMLGetSensitivity *handler = [[XMLGetSensitivity alloc] init];
        NSXMLParser *afParser = [operation responseXMLParser];
        [afParser setDelegate:(id)handler];
        
        [afParser parse];
        n = [handler sensitivity];
    }

    n = [[NSNumber alloc] initWithDouble:n.doubleValue];
    return n;
    //return TRUE;
}

/**
 *  
 *
 */
- (NSArray*) fetchCaretakers:(NSString*)email target:(id<NetworkData>)target requestType:(int)rtype
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            email, POST_EMAIL,
                            nil];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"requests/getCaretakersForPatient.php" parameters:params];
    
    __block id<NetworkData> delegate = target;
    __block int requestType = rtype;
   // __block int x = 1;
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
            success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
                
       // NSLog(@"Name: %@ %@", @"\n", [operation responseString]);
        XMLReadCaretakers *handler = [[XMLReadCaretakers alloc] init];
        [XMLParser setDelegate:handler];
        [XMLParser parse];
        [delegate DataArrived:[handler allCaretakers] requestType:requestType];                
    }
    failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , NSXMLParser *XMLParse) {
        // something went wrong
        [target DataArrived:nil requestType:0];
    }];

    [operation start];

    return nil;
}

/**
 * Fetches the patient associated with the provided email.
 * PARAM: email - A Caretaker's email
 */
- (LinkedAccount *) fetchPatient:(NSString *)email
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            email, POST_EMAIL,
                            nil];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"requests/getPatientForCaretaker.php" parameters:params];
    AFXMLRequestOperation *operation = [[AFXMLRequestOperation alloc] initWithRequest:request];
    
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperation:operation];
    [queue waitUntilAllOperationsAreFinished];
    if (debug)
        NSLog(@" data--fetchPatient \n %@", [operation responseString]);
    NSArray *result = nil;
    if (![operation hasAcceptableStatusCode] || [operation response] == nil){
        // operation failed
        
    }
    else {
        // check response, validate success
        XMLReadCaretakers *handler = [[XMLReadCaretakers alloc] init];
        NSXMLParser *afParser = [operation responseXMLParser];
        [afParser setDelegate:(id)handler];
        
        [afParser parse];
        result = [handler allCaretakers];
    }
    
    return [result objectAtIndex:0];

}




+ (UIAlertView*) createLoadingAlert 
{
    UIAlertView *alert;
    
    alert = [[LoadingAlert alloc] initWithTitle:@"Please wait..." message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
    [alert setDelegate:alert];
    
    return alert;
}

// Update user APNS key
- (void) uploadAPNSKey:(NSString*)key toUser:(NSString*)email{
    
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            email, POST_EMAIL,
                            key, POST_APNS,
                            nil];
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" 
                                                            path:@"account/updateAPNS.php" parameters:params];
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
            success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
                // Server took care of updating APNS key, no need to notify user    
    }
            failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , NSXMLParser *XMLParse) {
                // some failure
    }];
    
    [operation start];
}

/**
 *  Add a patient log of a seizure to the database.
 *  Param:  formattedStart - datetime in format yyyy-mm-dd hh:mm:ss
            formattedEnd   - datetime in format yyyy-mm-dd hh:mm:ss
            latitude       - valid numbers range from -90 to 90 degrees
            longitude      - valid numbers range from -180 to 180 degrees
            patientEmail   - the email of the patient to add this log for
 *  Usage:  Only Patients may add event logs.
 */
- (void)addPatientEventLog:(NSString *)formattedStart withEndTime:(NSString *)formattedEnd withLatitude:(NSNumber *)latitude 
             withLongitude:(NSNumber *)longitude withAccuracy:(NSNumber *)accuracy forPatient:(NSString *)patientEmail
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            patientEmail, POST_EMAIL,
                            formattedStart, POST_START_TIME,
                            formattedEnd, POST_END_TIME,
                            latitude, POST_LATITUDE,
                            longitude, POST_LONGITUDE,
                            accuracy, POST_ACCURACY, nil];
    
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"account/addPatientLog.php" parameters:params];
    
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
                success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
                    // Server took care of updating APNS key, no need to notify user    
    }
                failure:^(NSURLRequest *request , NSHTTPURLResponse *response , NSError *error , NSXMLParser *XMLParse){
    }];
    
    [operation start];
}

/**
 *  Get all of the logs needed for this account. PHP file will return XML of each log which will be interpreted
 *  into EventLog objects.
 *  
 *  Params: None. Data needed will be accessed through local data (accessing email, account type)
 *  Usage:  Caretakers may get the logs of a Patient that has a confirmed connection with them.
 *          Patients may only get their logs.
 *  Returns: An array of the EventLog objects that are created from the XML.
 */
- (NSArray*)getPatientEventLogs:(NSString *)requestingEmail forAccountType:(NSString *)accountType target:(id<NetworkData>)target requestType:(int)rtype;
{
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
    
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            requestingEmail, POST_EMAIL,
                            accountType, POST_ACC_TYPE, nil];
    
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"requests/getPatientLogs.php" parameters:params];
    
    __block id<NetworkData> delegate = target;
    __block int requestType = rtype;
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
                success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser)
                        {
//                            NSLog(@"Get Patient Event Logs successful");
                            
                            XMLReadEventLogs *handler = [[XMLReadEventLogs alloc] init];
                            [XMLParser setDelegate:handler];
                            [XMLParser parse];
                            [delegate DataArrived:[handler allEvents] requestType:requestType];
                        }
                failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParse)
                        {
//                            NSLog(@"Request for Patient Event Logs has failed.\n");
                            [delegate DataArrived:nil requestType:0];
                        }
    ];
    
    [operation start];
    
    return nil;
}

-(void) pushAlertForPatient:(NSString *)email location:(CLLocation *)location
{
    // do stuffff
    NSURL *url = [NSURL URLWithString:BASE_URL];
    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];

    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            email, POST_EMAIL,
                            [NSNumber numberWithDouble:location.coordinate.latitude], POST_LATITUDE,
                            [NSNumber numberWithDouble:location.coordinate.longitude], POST_LONGITUDE,
                            [NSNumber numberWithDouble:location.horizontalAccuracy], POST_ACCURACY,
                            nil];
    
    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"AlertCaretakersByPush.php" parameters:params];
    
    AFXMLRequestOperation *operation = [AFXMLRequestOperation XMLParserRequestOperationWithRequest:request 
                success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser)
                {
                }
                                        
        failure:nil
    ];
//    NSLog(@"send PUSH NOTIFCATOIN");
    [operation start];
}

@end
